package com.matt.service.impl;

import com.matt.commons.dto.sso.AreaDTO;
import com.matt.commons.dto.sso.StaffDTO;
import com.matt.commons.exception.BusinessException;
import com.matt.domain.Classes;
import com.matt.domain.course.CoursePlanClasses;
import com.matt.domain.record.LiveRecord;
import com.matt.domain.rel.RelChildrenLiveRecord;
import com.matt.foundation.DO.ChildClassesDO;
import com.matt.foundation.DO.ChildrenCheckRecordDO;
import com.matt.foundation.DO.ChildrenCourseItemDO;
import com.matt.foundation.constant.CourseConstant;
import com.matt.foundation.constant.FeedsConstant;
import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.utils.DateUtil;
import com.matt.foundation.utils.annotation.OptsTrace;
import com.matt.foundation.vo.LiveRecordCourseVo;
import com.matt.foundation.vo.liveRecord.BaseInfoVo;
import com.matt.foundation.vo.liveRecord.RecordListVo;
import com.matt.foundation.vo.observation.LiveRecordClassesVo;
import com.matt.repository.ClassesRepository;
import com.matt.repository.base.ChildChildrenCourseItemRepository;
import com.matt.repository.base.ChildChildrenExtendRepository;
import com.matt.repository.base.ChildrenLiveRecordRepository;
import com.matt.repository.course.CoursePlanClassesRepository;
import com.matt.repository.record.LiveRecordRepository;
import com.matt.repository.record.LoginRecordRepository;
import com.matt.repository.rel.RelChildrenLiveRecordRepository;
import com.matt.repository.rel.RelClassesChildrenRepository;
import com.matt.repository.rel.RelClassesTeacherRepository;
import com.matt.service.*;
import com.matt.service.remoteCall.SsoCallService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

/**
 * *******************************
 * Created by Ron.
 * form com.matt
 * on 2017/8/3
 * *******************************
 */
@Service
@Slf4j
public class LiveRecordServiceImpl implements LiveRecordService {

    @Autowired
    private LiveRecordRepository liveRecordRepository;

    @Autowired
    private UploadService uploadService;

    @Autowired
    private RelChildrenLiveRecordRepository relChildrenLiveRecordRepository;

    @Autowired
    private ChildrenLiveRecordRepository childrenLiveRecordRepository;

    @Autowired
    private RelClassesTeacherRepository relClassesTeacherRepository;

    @Autowired
    private SsoCallService ssoCallService;

    @Autowired
    private LoginRecordRepository loginRecordRepository;

    @Autowired
    private ChildrenService childrenService;

    @Autowired
    private ChildChildrenExtendRepository childChildrenExtendRepository;

    @Autowired
    private ChildChildrenCourseItemRepository childChildrenCourseItemRepository;

    @Autowired
    private CoursePlanClassesRepository coursePlanNurseryClassesRepository;

    @Autowired
    private ClassesRepository classesRepository;

    @Autowired
    private RelClassesChildrenRepository relClassesChildrenRepository;

    @Autowired
    private FeedsService feedsService;

    @Autowired
    private WxPushService wxPushService;

    @Autowired
    private GreenContentService greenContentService;

    @Value("${spring.redis.host}")
    private String host;

    @Transactional
    @OptsTrace(code = "0451")
    @Override
    public LiveRecord addLiveRecord(String title, String content, String resourceUrl, String[] childrenIds, Integer mediaType, Integer category, String coursePlanId, StaffDTO staff, AreaDTO area) {

//        if(!greenContentService.doTextAction(content)){
//            throw new BusinessException(ErrorCode.CHECK_STATUS_ERROR, "包含不适合发布的内容");
//        }

        String staffId = staff.getId();
        String areaId = area.getId();

        String headImgUrl =  staff.getHeadImgUrl();

        LiveRecord liveRecord = LiveRecord.of(title, content, category, resourceUrl, "", staffId, staff.getRealName(), areaId, mediaType, coursePlanId, headImgUrl);
        liveRecordRepository.save(liveRecord);
        for (String childId : childrenIds) {
            // RelClassesChildren relClassesChildren =  relClassesChildrenRepository.findFirstByChildrenId(childId);
            //  String classesId = relClassesChildren.getClassesId();
            //  Classes classes = classesRepository.getOne(classesId);
            //   String classesName = classes.getName();

            //  RelChildrenLiveRecord relChildrenLiveRecord = new RelChildrenLiveRecord(liveRecord.getId(), childId,classesId,classesName);
            RelChildrenLiveRecord relChildrenLiveRecord = new RelChildrenLiveRecord(liveRecord.getId(), childId);
            relChildrenLiveRecordRepository.save(relChildrenLiveRecord);

            //添加动态
            if (mediaType ==2)
                feedsService.save(staffId, childId, areaId, "", FeedsConstant.NURSERY, title, content,"", resourceUrl, liveRecord.getId());
            else if (mediaType ==1)
                feedsService.save(staffId, childId, areaId, "", FeedsConstant.NURSERY, title, content, resourceUrl,"", liveRecord.getId());
            else
                feedsService.save(staffId, childId, areaId, "", FeedsConstant.NURSERY, title, content,"", "", liveRecord.getId());
        }

        wxPushService.pushLiveRecord(liveRecord,null);
        return liveRecord;
    }


    @Transactional
    @OptsTrace(code = "0451")
    @Override
    public LiveRecord addLiveRecord(String title, String content, MultipartFile[] files, String[] childrenIds, Integer mediaType, Integer category, String coursePlanId, StaffDTO staff, AreaDTO area) {

        String staffId = staff.getId();
        String areaId = area.getId();

        String resourceUrl = uploadService.uploadLiveRecordImg(staffId, mediaType, files);

        return addLiveRecord(title, content, resourceUrl, childrenIds, mediaType, category, coursePlanId, staff, area);
    }

    @Override
    public Page<RecordListVo> getRecordPage(String staffId, Integer pageNum, Integer pageSize) {
        Specification<LiveRecord> specification = new Specification<LiveRecord>() {
            @Override
            public Predicate toPredicate(Root<LiveRecord> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                if (StringUtils.isNotBlank(staffId))
                    predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("operatorId"), staffId)));
                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("deleted"),false )));
                query.where(predicates.toArray(new Predicate[predicates.size()]));
                query.orderBy(criteriaBuilder.desc(root.get("created")));
                return query.getRestriction();
            }
        };
        Page<LiveRecord> liveRecordPage = liveRecordRepository.findAll(specification, PageRequest.of(pageNum, pageSize));
        List<RecordListVo> list = Lists.newArrayList();
//        liveRecordPage.getContent().stream().forEach(o -> {
//            //TODO 优化这部分
//            List<Object[]> objects = childrenLiveRecordRepository.findChildrenByLiveRecord(o.getId());
//            List<RecordChildVo> childrenList = objects.stream().map(r -> RecordChildVo.of(r)).collect(Collectors.toList());
//            RecordListVo vo = RecordListVo.of(o, childrenList);
//            list.add(vo);
//        });

        return new PageImpl(list, PageRequest.of(pageNum, pageSize), liveRecordPage.getTotalElements());
    }


    @Override
    public Page<RecordListVo> getRecordPageByAreaId(String areaId, Integer pageNum, Integer pageSize) {
        Specification<LiveRecord> specification = new Specification<LiveRecord>() {
            @Override
            public Predicate toPredicate(Root<LiveRecord> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                if (StringUtils.isNotBlank(areaId))
                    predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("areaId"), areaId)));
                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("deleted"),false )));
                query.where(predicates.toArray(new Predicate[predicates.size()]));
                query.orderBy(criteriaBuilder.desc(root.get("created")));
                return query.getRestriction();
            }
        };
        Page<LiveRecord> liveRecordPage = liveRecordRepository.findAll(specification, PageRequest.of(pageNum, pageSize));
//        List<RecordListVo> list = Lists.newArrayList();
//        liveRecordPage.getContent().stream().forEach(o -> {
////            List<Object[]> objects = childrenLiveRecordRepository.findChildrenByLiveRecord(o.getId());
////            List<RecordChildVo> childrenList = objects.stream().map(r -> RecordChildVo.of(r)).collect(Collectors.toList());
//            RecordListVo vo = RecordListVo.of(o, null);
//            list.add(vo);
//        });

        Page<RecordListVo> ret = liveRecordPage.map(o->RecordListVo.of(o, null));

        return ret;
    }

    @Override
    public BaseInfoVo statisticsInfo(StaffDTO staff, AreaDTO area) {

        String staffId = staff.getId();

        Date today = new Date();
        String todayStr = DateUtil.millisToDateTime(today.getTime(), "yyyy-MM-dd");
        Map<String, Date> dayMap = DateUtil.getCurrentDayBeginAndEnd(todayStr);
        List<LiveRecord> daysInfo = liveRecordRepository.findByOperatorIdAndDeletedAndCreatedBetween(staffId, false, dayMap.get("beg"), dayMap.get("end"));
        Date weekBegin = DateUtil.getWeekBegin(today);
        List<LiveRecord> weekInfo = liveRecordRepository.findByOperatorIdAndDeletedAndCreatedBetween(staffId, false, weekBegin, today);

        Integer classesNum = relClassesTeacherRepository.countByStaffId(staffId);

        Integer days = (int) DateUtil.betweenDays(new Date(staff.getLastLogin()), today);
        Integer loginTimes = loginRecordRepository.countByStaffId(staffId);

        List<LiveRecord> totalInfo = liveRecordRepository.findByOperatorIdAndDeleted(staffId, false);

        return BaseInfoVo.of(staffId, staff.getRealName(), staff.getHeadImgUrl(), daysInfo, weekInfo, totalInfo, area.getName(), classesNum, loginTimes, days);
    }

    @Override
    public List<LiveRecordClassesVo> getChildrenByArea(String areaId) {
        //所有激活的宝宝
        List<ChildClassesDO> allChildren = childChildrenExtendRepository.findChildrenStatusActive(areaId);
        //托班
        List<ChildClassesDO> nurseryClassChildList = childChildrenExtendRepository.findChildrenClassesByStatus(areaId, CourseConstant.Category.NURSERY.codeOf());
        //早教
        List<ChildClassesDO> earlyClassesChildList = childChildrenExtendRepository.findChildrenClassesByStatus(areaId, CourseConstant.Category.EARLY.codeOf());
        //移除早教里面包含托班的学生
        for (ChildClassesDO child :nurseryClassChildList){
            ChildClassesDO vo = matchChild(child , earlyClassesChildList);
            if (Objects.nonNull(vo))
                earlyClassesChildList.remove(vo);
        }

        for (ChildClassesDO child :nurseryClassChildList){
            ChildClassesDO nurseryVo = matchChild(child , allChildren);
            if (Objects.nonNull(nurseryVo))
                allChildren.remove(nurseryVo);
        }
        for (ChildClassesDO child :earlyClassesChildList){
            ChildClassesDO earlyVo = matchChild(child , allChildren);
            if (Objects.nonNull(earlyVo))
                allChildren.remove(earlyVo);
        }

        List<LiveRecordClassesVo> list = Lists.newArrayList();
        list.addAll(LiveRecordClassesVo.mergeOfNursery(nurseryClassChildList));
        list.addAll(LiveRecordClassesVo.mergeOfEarly(earlyClassesChildList));
        list.addAll(LiveRecordClassesVo.mergeOfNoClasses(allChildren));
        return list;
    }

    private ChildClassesDO matchChild(ChildClassesDO child, List<ChildClassesDO> childList) {
        Optional<ChildClassesDO> vo = childList.stream().filter(o -> o.getId().equals(child.getId())).findAny();
        return vo.isPresent() ? vo.get() : null;
    }

    @Override
    public Map getChildrenByCourse(String coursePlanId, Integer category) {
         Map map = new HashMap();
        if (CourseConstant.Category.EARLY.codeOf() == category){

            CoursePlanClasses nurseryClasses = coursePlanNurseryClassesRepository.getOne(coursePlanId);
            Classes classes = classesRepository.getOne(nurseryClasses.getClassesId());

            List<ChildrenCourseItemDO> itemList = childChildrenCourseItemRepository.findByChildrenByCoursePlanId(coursePlanId);// children_course_item 存放上课记录
            List<LiveRecordCourseVo> orChildrenListVos = itemList.stream().map(o -> LiveRecordCourseVo.ofEarlyCourse(o)).collect(Collectors.toList());

            map.put("classesName", classes.getName());
            map.put("classesCategory", classes.getCategory());
            map.put("childrenVoList", orChildrenListVos);
            return map;
        }else {

            CoursePlanClasses nurseryClasses = coursePlanNurseryClassesRepository.getOne(coursePlanId);
            Classes classes = classesRepository.getOne(nurseryClasses.getClassesId());
            List<ChildrenCheckRecordDO> checkRecordDOList = childrenService.findChildCheckRecordByClasses(nurseryClasses.getClassesId());//返回考勤状态
            List<LiveRecordCourseVo> orChildrenListVos = checkRecordDOList.stream().map(o -> LiveRecordCourseVo.ofNurseryCourse(o)).collect(Collectors.toList());
            map.put("classesName", classes.getName());
            map.put("classesCategory", classes.getCategory());
            map.put("childrenVoList", orChildrenListVos);

            return map;
        }
    }


    @Override
    public Page<RecordListVo> getLiveRecordByPlanId(String coursePlanId, Integer pageNum, Integer pageSize) {
        Specification<LiveRecord> specification = new Specification<LiveRecord>() {
            @Override
            public Predicate toPredicate(Root<LiveRecord> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                if (StringUtils.isNotBlank(coursePlanId))
                    predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("coursePlanId"), coursePlanId)));
                predicates.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("deleted"), false)));
                query.where(predicates.toArray(new Predicate[predicates.size()]));
                query.orderBy(criteriaBuilder.desc(root.get("created")));
                return query.getRestriction();
            }
        };

        Page<LiveRecord> liveRecordPage = liveRecordRepository.findAll(specification, PageRequest.of(pageNum, pageSize));
        List<RecordListVo> list = Lists.newArrayList();
        liveRecordPage.getContent().stream().forEach(o -> {
            list.add(RecordListVo.of(o, null));
        });

        return new PageImpl(list, PageRequest.of(pageNum, pageSize), liveRecordPage.getTotalElements());
    }

    @Override
    public LiveRecord findById(String id) {
        return liveRecordRepository.getOne(id);
    }

    @Override
    public LiveRecord deleteLiveRecord(StaffDTO staff, String recordId) {

        LiveRecord liveRecord = liveRecordRepository.getByAreaIdAndId(staff.getAreaId(), recordId);
        if (Objects.isNull(liveRecord))
            throw new BusinessException(ErrorCode.ID_IS_ERROR, "ID错误");

        String operatorId = liveRecord.getOperatorId();
        if (!operatorId.equals(staff.getId()))
            throw new BusinessException(ErrorCode.PROMISSION_DELINED, "权限不足");

        liveRecord.setDeleted(true);
        liveRecordRepository.save(liveRecord);

        return liveRecord ;
    }
}
